/*
 * R4.c
 *      Created on: Oct 22, 2013
 *              Authors: Joseph DeLong, Justin Hamric, Alex Newcomer, Alex Bouvy
 */

typedef struct param {
        int      op_code;
        int      device_id;
        char     *buf_p;
        int      *count_p;
} param;

#include <string.h>
#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "mpx_supt.h"
#include "defines.h"
#include "mpx_pcb.h"

#define SYS_STACK_SIZE 1024

//Hidden Commands
void carrot(char quality, int quantity);
void clear(void);
void alias(char* fname, char* newname, char** cnames);

//R1 Command Prototypes
int commhand(); //added struct MPX_Q's to be passed to ALL functions as needed
void date(char* input_tok[6], int command_args);
int help(int argc, char *argv[6], char** cnames);
int ls(char *input[6], int command_args);
int r_exit(int *exit);
void version(void);

//R2 Procedure Prototypes
MPX_PCB *allocPCB(void);
int freePCB(MPX_PCB *pcbName);
MPX_PCB *setupPCB(char processName[9], int processClass, int priority);
void insert_blocked(MPX_PCB* pcb);
void insert_ready(MPX_PCB* pcb);
int removePCB(struct MPX_PCB* pcbJ, int queue);
void show_all();
void disp();
void show_ready();
void show_blocked();
void show_pcb(struct MPX_PCB* pcb);
void blockPCB(char processName[9]);
void unblockPCB(char processName[9]);
MPX_PCB* find_ready(char processName[9]);
MPX_PCB* find_blocked(char processName[9]);

//suggested R2 commands
void R2Init(); //this will initialize our queues
void R2Clean(); //this will clear queues, reclaim all memory allocated to PCBs in them

//R3 Procedure Protypes
void interrupt sys_call();
void interrupt dispatcher();
void load_procs();

//R3 Test Prototypes
void test1_R3();
void test2_R3();
void test3_R3();
void test4_R3();
void test5_R3();

//R4 Protops
void load_program(char dirName[40], char programName[9], int priority);
void terminate_process(char processName[9]);
void new_dispatch();

//GLOBALS
char prompt[255];
struct MPX_Q *ready, *blocked;
//G R3
unsigned char sys_stack[SYS_STACK_SIZE];
unsigned short new_ss = NULL;
unsigned short new_sp = NULL;
unsigned short ss_save = NULL;
unsigned short sp_save = NULL;
int iglobal;
int flagyyflaggedyflag = 0;
int whyreturnaninthere;
MPX_PCB *dummy;
MPX_PCB *cop;
param *param_ptr;
FILE *fptr;
unsigned char *testptr;

/*
 * MAIN function
 * This is the meat and potatoes of the Appaloosa OS. Everything gets run through here.
 * parameters: NOTHING
 * returns: Integer representing normal operation/termination (0) or an error code (non-zero)
 */
int main(void) {
        sys_init(MODULE_R3);
        logo(); //animated welcome screen
        clear(); //clear the screen before allowing user input
        /*
         * THIS SHOULD BE WHERE WE ALLOCATE MEMORY FOR SYSTEM STARTUP,
         * AMONG OTHER THINGS
         */
        sys_set_vec(sys_call);
        R2Init();
        strcpy(prompt,"$$>\0");
        commhand();
        /*
         * THIS SHOULD BE WHERE WE DE-ALLOCATE ALL MEMORY BEFORE EXITING,
         * AMONG OTHER THINGS
         */
        R2Clean();
        sys_exit();
        return 0; //THIS SHOULD ACTUALLY BE A DYNAMICALLY OBTAINED INTEGER AS ERROR CODES ARE/ARE NOT CAPTURED AND HANDLED
}

//---------------------------------------------------------R1 COMMANDS---------------------------------------------------------//

/*
 * COMMHAND
 * Written by Alex Bouvy
 * Command Handler for Appaloosa OS
 * parameters: NONE
 * returns: Integer representing normal termination (0), or an error code (non-zero)
 */
int commhand() {
        char *output = NULL;
        int outputSize = 0;
        MPX_PCB* newpcb;
        int found;
        char* cnames[40];
        char input[256];
        char* input_tok[6];
        int bufferSize = 256;
        int promptLength;
        int gallop = 1; //set this horse to moving!
        int stringSize; //COMPILER IS NOT CORRECT, THIS VARIABLE IS USED
        int command_args=0;
        int max_args = 6;
        int i;
        int alphaFlag = 0;
        int whichQueue = 0;
        //------------comm literals----------------
        char c1[15]="ls\0";
        char c2[15]="date\0";
        char c3[15]="exit\0";
        char c4[15]="help\0";
        char c5[15]="version\0";
        char c6[15]="create-pcb\0";
        char c7[15]="delete-pcb\0";
        char c8[15]="block\0";
        char c9[15]="unblock\0";
        char c10[15]="suspend\0";
        char c11[15]="resume\0";
        char c12[15]="set-priority\0";
        char c13[15]="show-pcb\0";
        char c14[15]="show-all\0";
        char c15[15]="show-ready\0";
        char c16[15]="show-blocked\0";
        char c17[15]="alias\0";
        char c18[15]="load-procs\0";
        char c19[15]="dispatch\0";
        char d00[15]="mem\0";
        char d01[15]="qexit\0";
        char d02[15]="clear\0";
        char d03[15]="carrot\0";
        char d04[15]="disp\0";
        char d05[15] = "lp\0";
		char d06[15] = "whistle\0";
        char c20[15] = "terminate\0";
        cnames[0] = c1;
        cnames[1] = c2;
        cnames[2] = c3;
        cnames[3] = c4;
        cnames[4] = c5;
        cnames[5] = c6;
        cnames[6] = c7;
        cnames[7] = c8;
        cnames[8] = c9;
        cnames[9] = c10;
        cnames[10] = c11;
        cnames[11] = c12;
        cnames[12] = c13;
        cnames[13] = c14;
        cnames[14] = c15;
        cnames[15] = c16;
        cnames[16] = c17;
        cnames[17] = c18;
        cnames[18] = c19;
        cnames[19] = d00;
        cnames[20] = d01;
        cnames[21] = d02;
        cnames[22] = d03;
        cnames[23] = d04;
        cnames[24] = d05;
        cnames[25] = c20;
		cnames[26] = d06;
        //------------/comm literals---------------
        //loop until user enters the exit command
        while(gallop) { //while still kicking up dust
                alphaFlag = 0;
                whichQueue = 0;
                command_args=0;
                promptLength = strlen(prompt);
                sys_req(2,1, prompt, &promptLength);
                stringSize = sys_req(1, 1, input, &bufferSize);
                input_tok[0] = strtok(input," ");
                if(!strcmp(input_tok[0],"\n")){
                        continue;
                }
                else{
                        for(i=1;i<max_args;i++){
                                input_tok[i]=strtok(NULL," ");
                                if(input_tok[i]==NULL) break;
                                else command_args = i;
                        }
                }
                //hacky fix 1 for tokenization
                if(command_args==0){
                        strxfrm(input_tok[0],input_tok[0], strlen(input_tok[0]));
                        strcat(input_tok[0],"\0");
                }
                //hacky fix 2 for tokenization issue
                if(!(strcmp(input_tok[command_args],"\n"))){
                        input_tok[command_args] = NULL;
                        command_args--;
                }
                //command handling
                if(!(strcmp(input_tok[0],d00))) {
                        printf("Core Left: %ld\n",coreleft());
                        //TODO: sys_req() all printf() statements
                }
                else if(!(strcmp(input_tok[0],d01))) {//qexit
                        gallop=0;
                }
                else if(!(strcmp(input_tok[0],d04))) {
                        disp();
                }
                else if(!(strcmp(input_tok[0],c1))) {
                        ls(input_tok, command_args);
                }
                else if(!(strcmp(input_tok[0],c2))){
                        date(input_tok, command_args);
                }
                else if(!(strcmp(input_tok[0],c3))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c3);
                        }
                        else r_exit(&gallop);
                }
                else if(!(strcmp(input_tok[0],c4))) {
                        help(command_args, input_tok,cnames);
                }
                else if(!(strcmp(input_tok[0],c5))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c5);
                        }
                        else version();
                }
                //create-pcb
                else if(!(strcmp(input_tok[0],c6))) {
                        if(command_args!=3){
                                printf("Invalid number of arguments provided.\n");
                        }
                        else if(strlen(input_tok[1])>8){
                                printf("Invalid process name provided.\n");
                        }
                        else if(!(*input_tok[2]==49||*input_tok[2]==48)){
                                printf("Invalid process class value provided.\n");
                        }
                        else if(atoi(input_tok[3])>127||atoi(input_tok[3])<-128){
                                printf("Invalid priority value provided.\n");
                        }
                        else if(find_ready(input_tok[1]) != NULL){
                                printf("PCB '%s' already exists\n",input_tok[1]);
                        }
                        else if(find_blocked(input_tok[1]) != NULL){
                                printf("PCB '%s' already exists\n",input_tok[1]);
                        }
                        else{
                                for(i=0; i<strlen(input_tok[3]); i++){
                                        if(isalpha((input_tok[3])[i])){
                                                alphaFlag = 1;
                                        }
                                }
                                if(!alphaFlag){
                                        newpcb = setupPCB(input_tok[1],atoi(input_tok[2]),atoi(input_tok[3]));
                                        insert_ready(newpcb);
                                        printf("PCB '%s' created.\n",input_tok[1]);
                                } else {
                                        printf("parameter 3 is invalid\n");
                                }
                        }
                }
                //delete-pcb
                else if(!(strcmp(input_tok[0],c7))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish deleted must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1]);
                                if(newpcb != NULL){
                                        removePCB(newpcb, 1);
                                        freePCB(newpcb);
                                        printf("PCB '%s' deletion succcessful.\n",input_tok[1]);
                                }
                                else{
                                        newpcb = find_blocked(input_tok[1]);
                                        if(newpcb != NULL){
                                                removePCB(newpcb, 0);
                                                printf("PCB '%s' deletion succcessful.\n",input_tok[1]);
                                        }
                                        else printf("PCB not found.\n");
                                }
                        }
                }
                else if(!(strcmp(input_tok[0],c8))) {
                        if(input_tok[1] != NULL){
                                if(command_args == 1){
                                        if(strlen(input_tok[1]) <= 9){
                                                blockPCB(input_tok[1]);
                                        } else {
                                                printf("pcb name is too long.\n");
                                        }
                                } else {
                                        printf("Too many arguments.\n");
                                }
                        } else {
                                printf("Invalid first argument.\n");
                        }
                }
                else if(!(strcmp(input_tok[0],c9))) {
                        if(input_tok[1] != NULL){
                                if(command_args == 1){
                                        if(strlen(input_tok[1]) <= 9){
                                                unblockPCB(input_tok[1]);
                                        } else {
                                                printf("pcb name is too long.\n");
                                        }
                                } else {
                                        printf("Too many arguments.\n");
                                }
                        } else {
                                printf("Invalid first argument.\n");
                        }
                }
                //suspend
                else if(!(strcmp(input_tok[0],c10))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1]);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
                                if(newpcb != NULL){
                                        (*newpcb).isSuspended=1;
                                        printf("PCB '%s' suspended.\n",(*newpcb).processName);
                                } else printf("PCB not found.\n");
                        }
                }
                //resume
                else if(!(strcmp(input_tok[0],c11))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1]);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
                                if(newpcb != NULL){
                                        (*newpcb).isSuspended=0;
                                        printf("PCB '%s' resumed.\n",(*newpcb).processName);
                                } else printf("PCB not found.\n");
                        }
                }
                //set-priority
                else if(!(strcmp(input_tok[0],c12))) {
                        if(command_args!=2){
                                printf("Invalid number of arguments provided.\n");
                        }
                        else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB specified must be 8 characters or less.\n");
                        }
                        else if(atoi(input_tok[2])>127||atoi(input_tok[2])<-128){
                                printf("Invalid priority specified.\n");
                        }
                        else{
                                for(i=0; i<strlen(input_tok[2]); i++){
                                        if(isalpha((input_tok[2])[i])){
                                                alphaFlag = 1;
                                        }
                                }
                                if(!alphaFlag){
                                        newpcb = find_ready(input_tok[1]);
                                        if(newpcb == NULL){
                                                newpcb = find_blocked(input_tok[1]);
                                                whichQueue = 1;
                                        }
                                        if(newpcb != NULL){
                                                (*newpcb).priority=atoi(input_tok[2]);
                                                if(!whichQueue){
                                                        removePCB(newpcb, 1);
                                                        insert_ready(newpcb);
                                                }
                                                printf("PCB '%s' priority changed.\n",(*newpcb).processName);
                                        } else printf("PCB not found.\n");
                                }else printf("Invalid priority specified.\n");
                        }
                }// end 12
                //show-pcb
                else if(!(strcmp(input_tok[0],c13))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish deleted must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1]);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1]);
                                if(newpcb != NULL){
                                        printf("Name: %s\n",(*newpcb).processName);
                                        printf("Class: %d\n",(*newpcb).processClass);
                                        printf("State: %d\n",(*newpcb).pcb_state);
                                        printf("Suspended: %d\n",(*newpcb).isSuspended);
                                        printf("Prio: %d\n",(*newpcb).priority);
                                } else printf("PCB not found.\n");
                        }
                }
                //show-all
                else if(!(strcmp(input_tok[0],c14))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c14);
                        }
                        else {
                                show_all();
                        }
                }
                //show-ready
                else if(!(strcmp(input_tok[0],c15))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c15);
                        }
                        else show_ready();
                }
                //show-blocked
                else if(!(strcmp(input_tok[0],c16))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c16);
                        }
                        else show_blocked();
                }
                //alias
                else if(!(strcmp(input_tok[0],c17))) {
                        if(command_args!=2){
                                printf("Invalid number of arguments provided.\n");
                        }
                        else if(strlen(input_tok[2])>15){
                                printf("New command name must be less than 15 characters.\n");
                        }
                        else alias(input_tok[1],input_tok[2],cnames);
                }
                //load-procs
                else if(!(strcmp(input_tok[0],c18))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c18);
                        }
                        else load_procs();
                }
                //dispatch
                else if(!(strcmp(input_tok[0],c19))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c19);
                        }
                        else dispatcher();
                }
				else if(!(strcmp(input_tok[0],c20))) {
					input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n",c19);
                        }
                        else{
							terminate_process(input_tok[1]);
						}
                }
				
                else if(!(strcmp(input_tok[0],d02))) {//CLEAR SCREEN
                        clear();
                }
                else if(!(strcmp(input_tok[0],d03))) {//CHANGE PROMPT
                        if(input_tok[1] != NULL && input_tok[2] != NULL) { //if got 2 parameters
                                i = strlen(input_tok[1]);
                                if(i == 1) { //if parameter 1 is exactly one character
                                        if((input_tok[1][0] >= 65 && input_tok[1][0] < 91) || (input_tok[1][0] >= 97 && input_tok[1][0] < 123)) { //if parameter 1 is only A-Z or a-z
                                                for(i = 0; i < strlen(input_tok[2]) - 1; i++) { //look through all characters of parameter 2
                                                        if(!isdigit(input_tok[2][i])) { //if current char is not a digit
                                                                found = 0;
                                                                break;
                                                        }
                                                        else { //parameter 2 is all digits
                                                                found = 1;
                                                        }
                                                }
                                                if(found) {
                                                        i = strlen(input_tok[2]);
                                                        input_tok[2][i - 1] = '\0';
                                                        carrot(input_tok[1][0],atoi(input_tok[2]));
                                                }
                                                else {
                                                        printf("Parameter 2 must be an integer only.\n");
                                                }
                                        }
                                        else {
                                                printf("Parameter 1 must be a single character only, whose value is A-Z.\n");
                                        }
                                }
                                else {
                                        printf("Parameter 1 must be a SINGLE character.\n");
                                }
                        }
                        else {
                                printf("This command must have two arguments: a single character and an integer.\n");
                        }
                }
                //load-program
                else if (!(strcmp(input_tok[0], d05))){
                                input_tok[3][strlen(input_tok[3])-1] = '\0';
                                if(command_args!=3){
                                        printf("Invalid number of arguments provided.\n");
                                }
                                else if(isalpha(*input_tok[3])){
                                        printf("Priority provided must be an integer.\n");
                                }
                                else{
                                        printf("Loading Program\n");
                                        
                                        load_program(input_tok[1], input_tok[2],atoi(input_tok[3]));
                                        //load_program(char dirName[40], char programName[9], int priority
                                        } 
                                }
				else if(!(strcmp(input_tok[0], d06))) {
					if(command_args > 1) {
						printf("You cannot whistle with anything but your lips. Try to use no parameters.\n");
						}
					else {
						logo();
						clear();
					}
				}
                else printf("Command '%s' not recognized\n",input_tok[0]);
        }
        return 0;
}

/* DATE function
 * Written by: Alex Newcomer
 * Command: date (-s yyyy mm dd)
 * If the command, date, is submitted to the terminal, the date is displayed.
 * If the command is submitted with the -s flag and an 8 digit number, if the date is valid, the system date will be set to the provided date
 * If the date submitted is not valid, a message will be sent to the terminal saying so.
 */
typedef struct date_record {
        int day;
        int month;
        int year;
} date_record;

void date(char* input_tok[6], int command_args){
        int i, j;
        int daysInFebruary;
        int foundACharacter = 0;
        date_record currentDate, newDate;
        if(command_args == 4){
                //error check
                if(abs((strncmp(input_tok[1], "-s", 2)))){
                        // user entered invalid first arg
                        printf("date -> First argument is an invalid switch.\n");
                } else if(!(strncmp(input_tok[1], "-s", 2))){
                        //Alex's 9/19/2013 fixing the digit detection issue
                        foundACharacter = 0;
                        for(j=2; j < 5; j++){
                                for(i=0; i < strlen(input_tok[j]); i++){
                                        if(isalpha(input_tok[j][i])){
                                                foundACharacter = 1;
                                        }
                                }
                        }
                        if(foundACharacter){
                                printf("date -> You must enter digits not characters.\n");
                        }
                        //end Alex 9/19/2013
                        else
                                //check for yyyy(2) mm(3) dd(4), valid, not leapyear.
                                if(atoi(input_tok[3]) > 12 || atoi(input_tok[3]) < 1){
                                        //month too big
                                        printf("date -> too many months\n");
                                } else {
                                        //months and years are OK, check valid days
                                        //if february
                                        if(atoi(input_tok[3]) == 2){
                                                int leap = 0;
                                                if(atoi(input_tok[2])%400 == 0){
                                                        leap = 1;
                                                } else if (atoi(input_tok[2])%100 == 0){
                                                        leap = 0;
                                                } else if(atoi(input_tok[2])%4 == 0){
                                                        leap = 1;
                                                } else {
                                                        leap = 0;
                                                }
                                                if(leap){
                                                        daysInFebruary = 29;
                                                } else {
                                                        daysInFebruary = 28;
                                                }
                                                if(atoi(input_tok[4]) <= daysInFebruary){
                                                        //call date
                                                        date(input_tok, command_args);
                                                } else {
                                                        //exit with error (leap year)
                                                        printf("date -> leap year violation\n");
                                                }
                                        } else {//not february
                                                switch(atoi(input_tok[3])){
                                                case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                                                        if((atoi(input_tok[4]) <= 31) && ( strlen(input_tok[2]) < 6) ){
                                                                //set date
                                                                newDate.month = atoi(input_tok[4]);
                                                                newDate.year = atoi(input_tok[2]);
                                                                newDate.day = atoi(input_tok[3]);
                                                                sys_set_date(&newDate);
                                                        } else {
                                                                printf("date -> input error\n");
                                                        }
                                                        break;
                                                case 4: case 6: case 9: case 11:
                                                        if(( atoi(input_tok[4]) <= 30 ) && ( strlen(input_tok[2]) < 6)){
                                                                //set date
                                                                newDate.month = atoi(input_tok[4]);
                                                                newDate.year = atoi(input_tok[2]);
                                                                newDate.day = atoi(input_tok[3]);
                                                                sys_set_date(&newDate);

                                                        } else {
                                                                printf("date -> your days are invalid\n");
                                                        }
                                                        break;
                                                }
                                        }
                                }
                }
                //date(input_tok, command_args);
        } else if(command_args != 0){
                printf("date -> You have entered the wrong number of arguments\n");
        } else { //no args, display the date!
                sys_get_date(&currentDate);
                printf("%d, %d, %d\n", currentDate.day, currentDate.month, currentDate.year);
        }
}

/*
 * HELP command function
 * Written by Joseph DeLong
 * parameter argc: Integer representing the number of command arguments passed in
 * parameter argv: Pointer to an array of character strings representing the specific command(s) the USER is requesting help for
 * returns 0 if all went well or another integer, depending on the appropriate error code
 */
int help(int argc, char *argv[6], char** cnames) {
        int returnVal = 0;
        if(argc < 1 || strcmp(argv[0],"\0") == 0) {
                printf( "You have invoked the HELP command. For more specific help, type HELP [CMD],\n"
                                "where [CMD] is the command you would like help for.\n"
                                "\n"
                                "\tCommand\t| Brief Description\n"
                                "________________|_______________________________________________________________"
                                "%15s\t| Display/Set the current system date\n"
                                "%15s\t| Exit the system\n"
                                "%15s\t| Display the contents of the Present Working Directory\n"
                                "%15s\t| Display the current version of the OS\n"
                                "%15s\t| Creates a new PCB, with a unique, user-specified name\n"
                                "%15s\t| Deletes the user-specified PCB from the system\n"
                                "%15s\t| Blocks the user-specified PCB\n"
                                "%15s\t| Unblocks the user-specified PCB\n"
                                "%15s\t| Suspends the user-specified PCB\n"
                                "%15s\t| Resumes the user-specified suspended PCB\n"
                                "%15s\t| Sets the user-specified PCB to the user-specified priority\n"
                                "%15s\t| Shows the user-specified PCB & its internal guts\n"
                                "%15s\t| Shows all PCBs currently in the READY state\n"
                                "%15s\t| Shows all PCBs currently in the BLOCKED state\n"
                                "%15s\t| Shows all PCBs\n"
                                "%15s\t| Changes name of a command\n"
                                "%15s\t| Loads a program from the specified file and path name\n"
                                "%15s\t| Calls the Program dispatcher\n"
                                "\n",cnames[1],cnames[2],cnames[0],cnames[4],cnames[5],cnames[6],cnames[7],cnames[8],cnames[9],cnames[10],cnames[11],cnames[12],cnames[14],cnames[15],cnames[13],cnames[16],cnames[24],cnames[18]);
        }
        else {
                argv[1][strlen(argv[1])-1] = '\0';
                //Secret / Extra Commands
                if(strcmp(argv[1],cnames[22]) == 0) {
                        printf( "This has something to do with getting on Appaloosa's good side. Maybe she will\n"
                                        "let you ride her?\n");
                }
                else if(strcmp(argv[1],cnames[21]) == 0) {
                        printf("This command clears the screen.\n");
                }
                //R1 Commands
                else if(strcmp(argv[1],cnames[1]) == 0) {
                        printf( "To SHOW the current date, use date.\n"
                                        "To SET the system date, use date -s YYYY MM DD.\n"
                                        "You may enter negative years, indicating BCE.\n"
                                        "Months must be between 1 and 12.\n"
                                        "Days must not exceed their respective months.\n"
                                        "Leap year support is included.\n");
                }
                else if(strcmp(argv[1],cnames[2]) == 0) {
                        printf( "This command will exit the Appaloosa OS. Make sure you have saved your work\n"
                                        "before exiting.\n");
                }
                else if(strcmp(argv[1], cnames[3]) == 0) {
                        printf("Yes, this is the help command.\n");
                }
                else if(strcmp(argv[1],cnames[0]) == 0) {
                        printf("This command displays the contents of the Current Directory.\n");
                }
                else if(strcmp(argv[1],cnames[4]) == 0) {
                        printf( "This command shows the version and developer information for the current version\n"
                                        "of the Appaloosa OS.\n");
                }
                //R2 Commands
                else if(strcmp(argv[1], cnames[5]) == 0) {
                        printf( "This command accepts 3 arguments:.\n"
                                        "\tA character string (up to 9 characters long), indicating the NAME of the PCB\n"
                                        "\tAn integer, representing the Process Class of this PCB\n\t\t(0 = System, 1 = Application)\n"
                                        "\tAn integer, representing the Priority of this PCB (-128 to 127)\n");
                }
                else if(strcmp(argv[1], cnames[6]) == 0) {
                        printf( "This command deletes the specified PCB, free-ing its associated memory.\n"
                                        "It must have 1 argument passed to it: the name of the PCB to be\n"
                                        "deleted.\n");
                }
                else if(strcmp(argv[1], cnames[7]) == 0) {
                        printf("This command places the specified PCB into the blocked queue.\n"
                                        "It must have 1 argument passed to it: the name of the PCB to be blocked.\n");
                }
                else if(strcmp(argv[1], cnames[8]) == 0) {
                        printf("This command places the specified PCB into the ready queue. It\n"
                                        "takes in 1 argument: the name of the PCB to be unblocked.\n");
                }
                else if(strcmp(argv[1], cnames[9]) == 0) {
                        printf("This command sets the suspended flag of the specified PCB to 1. It\n"
                                        "takes in 1 argument: the name of the PCB to be suspended.\n");
                }
                else if(strcmp(argv[1], cnames[10]) == 0) {
                        printf("This command sets the suspended flag of the specified PCB to 0. It\n"
                                        "takes in 1 argument: the name of the PCB to be resumed.\n");
                }
                else if(strcmp(argv[1], cnames[11]) == 0) {
                        printf( "This command takes in 2 arguments:\n"
                                        "\tA character string, representing the name of the PCB\n"
                                        "\tAn integer, representing the new Priority of the PCB\n");
                }
                else if(strcmp(argv[1], cnames[12]) == 0) {
                        printf("This command will display the internal information contained\n"
                                        "the specified PCB. It takes in 1 argument: The\n"
                                        "name of the PCB to be displayed.\n");
                }
                else if(strcmp(argv[1], cnames[13]) == 0) {
                        printf( "This command displays information contained within all PCBs currently in the\n"
                                        "Ready Queue.\n");
                }
                else if(strcmp(argv[1], cnames[14]) == 0) {
                        printf( "This command displays information contained within all PCBs currently in the\n"
                                        "Blocked Queue.\n");
                }
                else if(strcmp(argv[1], cnames[15]) == 0) {
                        printf("This command displays information contained within all PCBs.\n");
                }
                else if(strcmp(argv[1], cnames[16]) == 0) {
                        printf( "This command allows user to change the name of a given command to a name"
                                        "provided.\n");
                }
                else if(strcmp(argv[1], cnames[17]) == 0) {
                        printf("This command loads the test processes for Module R3.\n");
                }
                else if(strcmp(argv[1], cnames[18]) == 0) {
                        printf("This function dispatched the highest priority non-suspended PCB in the ready queue\n");
                }
                else if(strcmp(argv[1], cnames[24]) == 0) {
                        printf("This function loads programs from an external file.\n");
                }
                else if(strcmp(argv[1], cnames[25]) == 0) {
                        printf("This function terminates the specified process.\n");
                }
                else {
                        printf("You have requested help for a non-existent command: %s\n",argv[1]);
                        returnVal = -56712; //placeholder for error code return (if we are going to do this)
                }
        }
        return returnVal;
}

/*
 * DIRECTORY function
 * Written by Justin Hamric
 * This function prints out the name and size (in bytes) of all files found in the current directory.
 */
int ls(char *input[6], int command_args) {
        char name_buf[40]; //can return a file name of length up to 20
        int buf_size = 40;
        long file_size_p; // size of returned file in bytes
        int i;
        int paginate = 0;
        char user_input[40];
        if(command_args == 0) {
                sys_open_dir("\0");
                while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) {
                        if(paginate>20){
                                printf("Press enter to proceed to the next page\n");
                                getch();
                                paginate = 0;
                        }
                        printf("%s of size %ld bytes.\n", name_buf, file_size_p);
                        paginate++;
                }
                sys_close_dir();
        }else if(command_args == 1) {
                input[1][strlen(input[1])-1] = '\0';
                //printf("One Argument: %s  length: %d \n", input[1], strlen(input[1]));
                if(sys_open_dir(input[1])>=0) {
                        while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) {
                                if(paginate>20){
                                        printf("Press enter to proceed to the next page\n");
                                        getch();
                                        paginate = 0;
                                }
                                printf("%s of size %ld bytes.\n", name_buf, file_size_p);
                                paginate++;
                        }
                }else {
                        printf("The directory could not be found.\n");
                }
                sys_close_dir();
        }
        else {
                printf("Too many arguments.\n");
        }
        return 0;
}

/* EXIT function
 * Written by Alex Bouvy
 * parameter *exit: an integer pointer, which indicates whether this function ran correctly so MAIN can continue to system cleanup
 */
int r_exit(int *exit) {
        char question[19] = "Really exit? (y/n)\n";
        char input_buffer[256];
        char original_input[256];
        char* input[6];
        int qlength = 19;
        int bufferSize = 256;
        int i;
        int command_args = 0;
        sys_req(2,1, question, &qlength); //print question
        sys_req(1, 1, input_buffer, &bufferSize); //get answer to question
        strcpy(original_input,input_buffer);
        strxfrm(original_input,original_input, strlen(original_input));
        input[0] = strtok(input_buffer," ");
        for(i=1;i<6;i++){
                input[i]=strtok(NULL," ");
                if(input[i]==NULL) break;
                else command_args = i;
        }
        if(strlen(input[0])>1){
                strxfrm(input[0],input[0], strlen(input[0]));
        }
        strcat(input[0],"\0");
        //hacky fix for other tokenization issue
        if(command_args==1){
                if(!(strcmp(input[1],"\n"))){
                        command_args=0;
                        input[1] = NULL;
                }
        }
        if(command_args>0){
                printf("'%s' is not valid.\n",original_input);
        }
        else if(!(strcmp(input[0],"Y\0"))) {
                *exit = 0;
        }
        else if(!(strcmp(input[0],"y\0"))) {
                *exit = 0;
        }
        else if(!(strcmp(input[0],"N\0"))) {
                //do nothing
        }
        else if(!(strcmp(input[0],"n\0"))) {
                //do nothing
        }
        else printf("'%s' is not valid.\n",input[0]);
        return 0;
}

/*
 * VERSION function
 * Written by Joseph DeLong
 * parameters: NONE
 * returns: NOTHING
 */
void version(void) {
        int size = sizeof(VERSION_INFO) - 1;
        sys_req(2, 1, VERSION_INFO, &size);// this info is held in defines.h
}
//--------------------------------------------------------/R1 COMMANDS---------------------------------------------------------//

//---------------------------------------------------------R2 COMMANDS---------------------------------------------------------//
void R2Init() {
        ready = sys_alloc_mem(sizeof(struct MPX_Q));
        blocked = sys_alloc_mem(sizeof(struct MPX_Q));
        (*ready).count = 0;
        (*ready).head = NULL;
        (*ready).tail = NULL;
        (*blocked).count = 0;
        (*blocked).head = NULL;
        (*blocked).tail = NULL;
}

/*
 * R2Clean Function
 * Created on: Sep 30, 2013
 * Written by: Joseph DeLong and Alex J. Newcomer
 * Calls deletePCB()(which frees the pcb's) for all and then frees the queues
 * NOTE: This should be checked with the mem function
 */
void R2Clean() {
        int i;
        MPX_PCB *temp = (*ready).head;
        MPX_PCB *temp1;
        //clear ready
        for(i = 0; i < (*ready).count; i++) {
                temp1 = (*temp).next;
                freePCB(temp);
                temp = temp1;
        }
        //clear blocked
        temp = (*blocked).head;
        for(i = 0; i < (*blocked).count; i++) {
                temp1 = (*temp).next;
                freePCB(temp);
                temp = temp1;
        }
        sys_free_mem(ready);
        sys_free_mem(blocked);
}

/* Alex Bouvy
 * freePCB()
 * Uses the support function sys_free_mem to free all the memory associated with a pcb
 *      Params:
 *      Pointer to pcb to free
 *      Returns:
 *      Nothing OR error/success code
 */
int freePCB(MPX_PCB* pcb){
        return sys_free_mem(pcb);
}

/* Alex Bouvy
 * allocPCB()
 * Uses the support function sys_alloc_mem(0 to allocate memory for a PCB
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */
MPX_PCB *allocPCB(){
        MPX_PCB* p;
        p = sys_alloc_mem(sizeof(MPX_PCB));
        return p;
}

/* Alex Bouvy
 * SetupPCB()
 * Procedures: Setup-PCB 19/32
 * CS 450 LAB Module R2 Feb. 1, 2013
 * Initializes the information in your PCB structure. Does not
 * insert into a queue. Calls Allocate-PCB(), sets state to
 * ready, not suspended (this will change later)
 * Parameters: Process Name, class, priority
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */
MPX_PCB* setupPCB(char procName[9], int processClass, int prio) {
        MPX_PCB* pcb;
        //initialize PCB structure:
        pcb = allocPCB();
        pcb->stack_base = sys_alloc_mem(SYS_STACK_SIZE);
        pcb->stack_top = pcb->stack_base + SYS_STACK_SIZE-sizeof(context);
        strcpy((*pcb).processName,procName);
        strcat((*pcb).processName,"\0");
        (*pcb).processID = 0;
        (*pcb).processClass = processClass; //system is 0, application is 1
        (*pcb).priority = prio;
        (*pcb).pcb_state = 1;
        (*pcb).isSuspended = 1;
        (*pcb).memorySize;
        (*pcb).load_address = 0;
        (*pcb).exec_address = 0;
        return pcb;
}

/*
 * CLEAR SCREEN function
 *  Created on: Sep 12, 2013
 *      Author: Joseph DeLong
 * parameters: NONE
 * returns: Nothing.
 */
void clear(void) {
        sys_req(3,1,((void *)0),((void *)0)); //CLEAR(3) the TERMINAL(1)
}

/*
 * CARROT function
 * Created on: Sep 7, 2013
 * Author: Joseph DeLong
 * Allows the user to feed the friendly Appaloosa. In return, she will accept any name you give her.
 * parameter QUALITY: A character representing the quality of the carrot offered to Appaloosa. Quality values are:
 *
 *              VALUE                   | QUALITY POINTS
 *              --------------------|---------------
 *              A(awful)                |       -10
 *              B(bitter)                       |       -5
 *              C(crisp)                        |       +5
 *              D(dirty)                        |       0
 *              E(erroneous)        |   -1
 *              F(flimsy)               |       -2
 *              G(good)                 |       +10
 *              H(horrible)             |       -11
 *              I(ideal)                |       +25
 *              J(just right)       |   +15
 *              K(killer)               |       +18
 *              L(lousy)                |       -7
 *              M(moldy)                |       -4
 *              N(normal)               |       +3
 *              O(orange)               |       +1
 *              P(poor)                 |       -4
 *              Q(quick)                |       +13
 *              R(rotten)               |       -17
 *              S(sweet)                |       +13
 *              T(tasty)                |       +8
 *              U(ugly)                 |       -4
 *              V(violent)              |       -9
 *              W(wobbly)               |       -2
 *              X(x-ray)                |       +7
 *              Y(yellow)               |       +1
 *              Z(zebra)                |       +3
 *
 * parameter QUANTITY: Integer representing the number of carrots offered to old faithful Appaloosa.
 * returns: Pointer to character string containing the new name Appaloosa accepts commands by.
 */
void carrot(char quality, int quantity) {
        char value[26] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
        int worth[26] = {-10,-5,5,0,-1,-2,10,-11,25,15,18,-7,-4,3,1,-4,13,-17,13,8,-4,-9,-2,7,1,3};
        int i;
        for(i = 0; i < 26; i++) {
                if(value[i] == toupper(quality)) {
                        if(worth[i] * quantity >= 100) {
                                //allow change
                                printf( "Appaloosa accepts your gracious gift of CARROT. What should her new PROMPT be?\n");
                                i = 255;
                                sys_req(1,1, prompt, &i); //get input from user
                                for(i = 0; i < strlen(prompt); i++) {
                                        if(prompt[i] == '\n') {
                                                prompt[i] = '\0';
                                                break;
                                        }
                                        else if(i == strlen(prompt) - 1) {
                                                prompt[i] = '\0';
                                                break;
                                        }
                                }
                                break;
                        }
                        else {
                                //disallow change
                                printf("Appaloosa turns her head away. Your gift of CARROT is sub-par at best.\n");
                                break;
                        }
                }
        }
}//have a nice day!

/* Alex Bouvy
 * show_ready()
 */
void show_ready(){
        int index;
        MPX_PCB* temp;
        int paginate = 0;
        int queueCurrent = 1;
        clear();
        printf("\n");
        printf("Ready Queue:\n\n");
        paginate = paginate + 3;
        temp = (*ready).head;
        for(index = 0; index<(*ready).count; index++){
                if(paginate>18){
                        printf("Press enter to proceed to the next page\n\n");
                        getchar();
                        paginate = 0;
                        clear();
                }
                printf("Name: %s\n",(*temp).processName);
                printf("Class: %d\n",(*temp).processClass);
                printf("State: %d\n",(*temp).pcb_state);
                printf("Suspended: %d\n",(*temp).isSuspended);
                printf("Prio: %d\n",(*temp).priority);
                printf("\n");
                paginate = paginate +6;
                temp = (*temp).next;
        }
        printf("\n");
        sleep(1);
        printf("Press enter to proceed to the next page\n\n");
        getchar();
        clear();
}

/* Alex Bouvy
 * show_blocked()
 */
void show_blocked(){
        int index;
        MPX_PCB* temp;
        int paginate = 0;
        int queueCurrent = 1;
        clear();
        printf("\n");
        printf("Blocked Queue:\n\n");
        paginate = paginate + 3;
        temp = (*blocked).head;
        for(index = 0; index<(*blocked).count; index++){
                if(paginate>18){
                        printf("Press enter to proceed to the next page\n\n");
                        getchar();
                        paginate = 0;
                        clear();
                }
                printf("Name: %s\n",(*temp).processName);
                printf("Class: %d\n",(*temp).processClass);
                printf("State: %d\n",(*temp).pcb_state);
                printf("Suspended: %d\n",(*temp).isSuspended);
                printf("Prio: %d\n",(*temp).priority);
                printf("\n");
                paginate = paginate + 6;
                temp = (*temp).next;
        }
        printf("\n");
        sleep(1);
        printf("Press enter to proceed to the next page\n\n");
        getchar();
        clear();
        printf("\n");
}

/* Alex Bouvy
 * show_blocked()
 */
void disp(){
        int index;
        MPX_PCB* temp;
        printf("\n");
        printf("Ready Queue:\n");
        temp = (*ready).head;
        for(index = 0; index<(*ready).count; index++){
                printf("%s %d\n",(*temp).processName,(*temp).priority);
                temp = (*temp).next;
        }
        printf("\n");
        printf("Blocked Queue:\n");
        temp = (*blocked).head;
        for(index = 0; index<(*blocked).count; index++){
                printf("%s %d\n",(*temp).processName,(*temp).priority);
                temp = (*temp).next;
        }
        printf("\n");
}

/* Alex Bouvy
 * show_all()
 */
void show_all(){
        show_ready();
        show_blocked();
}

/* Alex Bouvy
 * insert_blocked()
 */
void insert_blocked(struct MPX_PCB* new) {
        int index;
        if((*blocked).count==0){
                (*blocked).head = new;
                (*blocked).tail = new;
                (*new).next = NULL;
                (*new).prev = NULL;
                (*blocked).count++;
        }
        else{
                (*(*blocked).tail).next = new;
                (*new).prev = (*blocked).tail;
                (*blocked).tail = new;
                (*blocked).count++;
        }
}

/* Alex Bouvy
 * insert_ready()
 */
void insert_ready(struct MPX_PCB* new) {
        int index;
        int prio = (*new).priority;
        MPX_PCB* temp;
        MPX_PCB* prev;
        if((*ready).count==0){
                (*ready).head = new;
                (*ready).tail = new;
                (*new).next = NULL;
                (*new).prev = NULL;
                (*ready).count++;
        }
        else if(prio>(*(*ready).head).priority){
                (*new).next = (*ready).head;
                (*(*ready).head).prev = new;
                (*ready).head = new;
                (*ready).count++;
        }
        else{
                temp = (*ready).head;
                for(index = 0; index<(*ready).count; index++){
                        if((*new).priority>(*temp).priority){
                                (*prev).next = new;
                                (*new).prev = prev;
                                (*new).next = temp;
                                (*temp).prev = new;
                                (*ready).count++;
                                return;
                        }
                        prev = temp;
                        temp = (*temp).next;
                }
                (*prev).next = new;
                (*ready).tail = new;
                (*new).prev = prev;
                (*ready).count++;
        }
}

/* Alex Bouvy
 * removePCB()
 * queue 1 = ready, 0 = blocked
 */
int removePCB(struct MPX_PCB* pcbJ, int queue){
        //pcbJ is head
        if(queue){
                if(!strcmp((*(*ready).head).processName,(*pcbJ).processName)){
                        (*ready).head = (*(*ready).head).next;
                        (*(*ready).head).prev = NULL;
                }
                //pcbJ is tail
                else if((*pcbJ).next == NULL){
                        (*ready).tail = (*pcbJ).prev;
                        (*(*ready).tail).next = NULL;
                }
                //pcbJ is in middle
                else{
                        (*(*pcbJ).prev).next = (*pcbJ).next;
                        (*(*pcbJ).next).prev = (*pcbJ).prev;
                }
                (*ready).count--;
                return 1;
        } else {
                if(!strcmp((*(*blocked).head).processName,(*pcbJ).processName)){
                        (*blocked).head = (*(*blocked).head).next;
                        (*(*blocked).head).prev = NULL;
                }
                //pcbJ is tail
                else if((*pcbJ).next == NULL){
                        (*blocked).tail = (*pcbJ).prev;
                        (*(*blocked).tail).next = NULL;
                }
                //pcbJ is in middle
                else{
                        (*(*pcbJ).prev).next = (*pcbJ).next;
                        (*(*pcbJ).next).prev = (*pcbJ).prev;
                }
                (*blocked).count--;
                return 1;
        }
}

/*
 * FIND PCB
 * Written by Joseph DeLong and Alex J. Newcomer
 * Debugged by pimp daddy
 * Searches all queues for a process with the given name.
 * Parameters: Process Name
 * Returns:
 *      Pointer to the PCB if found
 *      NULL if error
 */
MPX_PCB* find_ready(char processName[9]) {
        MPX_PCB* temp;
        int found = 0, count = 0, count1 = 0;
        temp = (*ready).head;
        for(count = 0; count<(*ready).count; count++){
                if(!strcmp((*temp).processName,processName)) { //if names match
                        return temp;
                }
                temp = (*temp).next;
        }
        return NULL;
}

MPX_PCB* find_blocked(char processName[9]) {
        MPX_PCB* temp;
        int found = 0, count = 0, count1 = 0;
        temp = (*blocked).head;
        for(count = 0; count<(*blocked).count; count++){
                if(!strcmp((*temp).processName,processName)) { //if names match
                        return temp;
                }
                temp = (*temp).next;
        }
        return NULL;
}

//created by Alex J. Newcomer
void blockPCB(char processName[9]){
        MPX_PCB* temp;
        processName[strlen(processName)- 1] = '\0';
        temp = find_ready(processName);
        if(temp == NULL){
                temp = find_blocked(processName);
                if(temp == NULL){
                        printf("%s doesn't exist.\n", processName);
                } else {
                        printf("%s is already blocked.\n", processName);
                }
        } else {
                printf("'%s' blocked.\n",processName);
                removePCB(temp, 1);
                insert_blocked(temp);
        }
}

//created by Alex J. Newcomer
void unblockPCB(char processName[9]){
        MPX_PCB* temp;
        processName[strlen(processName)- 1] = '\0';
        temp = find_ready(processName);
        if(temp == NULL){
                temp = find_blocked(processName);
                if(temp == NULL){
                        printf("%s doesn't exist.\n", processName);
                } else {
                        printf("'%s' unblocked.\n",processName);
                        removePCB(temp, 0);
                        insert_ready(temp);
                }
        } else {
                printf("%s is already ready.\n", processName);
        }
}
/*
 * LOGO function
 * Written by Joseph DeLong
 * Displays an animated ASCII logo of a running horse, as well as a final load screen, with the name of the OS
 * parameters: NONE
 * returns: an Integer representing either 0 (normal operation/termination) or a non-zero number (error code)
 */
int logo(void) {
        //open all logo files
        int h,i,j,k;
        FILE *logo1 = fopen("logo01","r");
        FILE *logo2 = fopen("logo02","r");
        FILE *logo3 = fopen("logo03","r");
        FILE *logo4 = fopen("logo04","r");
        FILE *logo5 = fopen("logo05","r");
        FILE *logo6 = fopen("logo06","r");
        FILE *logo7 = fopen("logo07","r");
        FILE *logo8 = fopen("logo08","r");
        FILE *logoF = fopen("logoF","r");
        //make FILE array
        FILE *logos[8];
        logos[0] = logo1;
        logos[1] = logo2;
        logos[2] = logo3;
        logos[3] = logo4;
        logos[4] = logo5;
        logos[5] = logo6;
        logos[6] = logo7;
        logos[7] = logo8;
        //set up for iteration
        for (h = 0; h < 4; h++) { //number of animations
                //set seek position to start of files
                fseek(logo1,0,SEEK_SET);
                fseek(logo2,0,SEEK_SET);
                fseek(logo3,0,SEEK_SET);
                fseek(logo4,0,SEEK_SET);
                fseek(logo5,0,SEEK_SET);
                fseek(logo6,0,SEEK_SET);
                fseek(logo7,0,SEEK_SET);
                fseek(logo8,0,SEEK_SET);
                for(i = 0; i < 8; i++) { //number of frames
                        for(j = 0; j < 25; j++) { //number of rows in each frame
                                for(k = 0; k < 80; k++) { //number of characters in each row
                                        printf("%c", fgetc(logos[i]));
                                }
                                fgetc(logos[i]);//this should clear the newline character from being captured
                        }
                        delay(250); //wait a quarter of a second after each frame <dos.h>
                }
        }
        //display final load screen
        fseek(logoF,0,SEEK_SET);
        for(j = 0; j < 25; j++) { //number of rows
                for(k = 0; k < 80; k++) { //number of characters in each row
                        printf("%c", fgetc(logoF));
                }
                fgetc(logos[i]);//this should clear the newline character from being captured
        }
        delay(5000); //wait 5 seconds <dos.h>
        //close all logo files
        fclose(logo1);
        fclose(logo2);
        fclose(logo3);
        fclose(logo4);
        fclose(logo5);
        fclose(logo6);
        fclose(logo7);
        fclose(logo8);
        fclose(logoF);
        //exit
        return 0;
}

/*
 *ALIAS
 *Changes name of a function specified by user
 *Alex Bouvy
 */
void alias(char* fname, char* newname, char** cnames) {
        int i;
        int errCode = 0;
        int notFound = 0;
        newname[strlen(newname)- 1] = '\0';
        for(i = 0; i<40; i++){
                if(!strcmp(cnames[i],newname)){
                        errCode = 999;
                }
        }
        if(!errCode){
                for(i = 0; i<40; i++){
                        if(!strcmp(cnames[i],fname)){
                                strcpy(cnames[i],newname);
                                return;
                        }
                        notFound = 999;
                }
        }
        else printf("Operation not performed, command names must be unique.\n");
        if(notFound) printf("Command '%s' not found.\n",fname);
}

//--------------------------------------------------------/R2 COMMANDS---------------------------------------------------------//

/*
 * SEND function
 * Written by Joseph DeLong
 * parameter text:      A variable-sized character pointer (string)
 * returns:                     An integer value representing the results of text processing
 */
int send(char* text) {
        int size = 0;
        //
        size = sizeof(text);
        sys_req(2, 1, text, &size);
        return 0;
}

//---------------------------------------------------------R3 COMMANDS---------------------------------------------------------//

/*
 * sys_call()
 * Is the handler called by the system when the int 60h instruction is encountered.
 * Saves the state of the currently operating process, and calls dispatch() to get the next process.
 * parameters: NONE
 * returns: nothing
 */
void interrupt sys_call() {
        //Update stack top IS THIS CORRECT?
        cop->stack_top = (unsigned char*)MK_FP(_SS,_SP);
        //Access parameters that sys_req() placed on the stack for us:
        param_ptr = ( param*)(cop->stack_top + sizeof(context));
        //Switch to temporary stack:
        new_ss = FP_SEG(sys_stack);
        new_sp = FP_OFF(sys_stack) + SYS_STACK_SIZE;
        _SS = new_ss;
        _SP = new_sp;
        //Check parameters:
        if((*param_ptr).op_code == IDLE) {
                (*cop).pcb_state = READY; //set cop -> state to ready
                insert_ready(cop); //insert cop into ready queue
        }
        if((*param_ptr).op_code == EXIT) {
                sys_free_mem(cop->stack_base);
                freePCB(cop); //delete cop and free its memory
                cop = NULL; //set cop = null
        }
        dispatcher();
}

/*
 * dispatch()
 * Alex Newcomer
 * Prepares the first process of the ready queue for execution by switching to its stack.
 * parameters: NONE
 * returns: nothing
 */
void interrupt dispatcher() {
        flagyyflaggedyflag = 0;
        if(ss_save == NULL){
                ss_save = _SS;
                sp_save = _SP;
        }
        dummy = ready->head;
        for(iglobal = 0; iglobal < (*ready).count; iglobal++){
                if(!(dummy->isSuspended)){
                        //found the first non suspended pcb on the ready queue.
                        flagyyflaggedyflag = 1;
                        cop = dummy;
                        whyreturnaninthere = removePCB( cop, 1);
                        cop->pcb_state = RUNNING;
                        new_ss = FP_SEG(cop->stack_top);
                        new_sp = FP_OFF(cop->stack_top);
                        break;
                }
                dummy = dummy->next;
        }
        if(!flagyyflaggedyflag){
                cop = NULL;
                new_ss = ss_save;
                new_sp = sp_save;
                sp_save = NULL;
                ss_save = NULL;
        }
        _SS = new_ss;
        _SP = new_sp;
}

/*
 * load_procs
 */
void load_procs(void) {
        int i;
        MPX_PCB* tests[5];
        context* contexts[5];
        tests[0] = setupPCB("test0001", 1, 0);
        tests[1] = setupPCB("test0002", 1, 0);
        tests[2] = setupPCB("test0003", 1, 0);
        tests[3] = setupPCB("test0004", 1, 0);
        tests[4] = setupPCB("test0005", 1, 0);
        contexts[0] = (context*) tests[0]->stack_top;
        contexts[1] = (context*) tests[1]->stack_top;
        contexts[2] = (context*) tests[2]->stack_top;
        contexts[3] = (context*) tests[3]->stack_top;
        contexts[4] = (context*) tests[4]->stack_top;
        contexts[0]->IP = FP_OFF(&test1_R3);
        contexts[0]->CS = FP_SEG(&test1_R3);
        contexts[0]->FLAGS = 0x200;
        contexts[0]->DS = _DS;
        contexts[0]->ES = _ES;
        insert_ready(tests[0]);         
        contexts[1]->IP = FP_OFF(&test2_R3);
        contexts[1]->CS = FP_SEG(&test2_R3);
        contexts[1]->FLAGS = 0x200;
        contexts[1]->DS = _DS;
        contexts[1]->ES = _ES;
        insert_ready(tests[1]);         
        contexts[2]->IP = FP_OFF(&test3_R3);
        contexts[2]->CS = FP_SEG(&test3_R3);
        contexts[2]->FLAGS = 0x200;
        contexts[2]->DS = _DS;
        contexts[2]->ES = _ES;
        insert_ready(tests[2]);         
        contexts[3]->IP = FP_OFF(&test4_R3);
        contexts[3]->CS = FP_SEG(&test4_R3);
        contexts[3]->FLAGS = 0x200;
        contexts[3]->DS = _DS;
        contexts[3]->ES = _ES;
        insert_ready(tests[3]);         
        contexts[4]->IP = FP_OFF(&test5_R3);
        contexts[4]->CS = FP_SEG(&test5_R3);
        contexts[4]->FLAGS = 0x200;
        contexts[4]->DS = _DS;
        contexts[4]->ES = _ES;
        insert_ready(tests[4]);         
}

//--------------------------------------------------------/R3 COMMANDS---------------------------------------------------------//
// lots of dashes r4 commands lots more dashes

void load_program(char dirName[40], char programName[9], int priority){
        int SCP, LProg;
        int prog_len_p;//program length in bytes
        int start_offset_p;//
        MPX_PCB *pcb;
        context *pcbContext;
        //check args
        //NOTE IF PRIO NOT INCLUDED DEFAULT TO 0
        if(priority >= -128 && priority <= 127){
                if((find_ready(programName) == NULL)&&(find_blocked(programName) == NULL)){
                        //check program
                        SCP = sys_check_program(dirName, programName, &prog_len_p, &start_offset_p);
                        if(SCP == 0){
                                printf("Valid Program\n");
                                pcb = sys_alloc_mem(sizeof(MPX_PCB));
                                pcb->stack_base = sys_alloc_mem(SYS_STACK_SIZE);
                                pcb->stack_top = pcb->stack_base + SYS_STACK_SIZE-sizeof(context);
                                strcpy(pcb->processName,programName);
                                strcat(pcb->processName,"\0");
                                pcb->processID = 0;
                                pcb->processClass = 1; //system is 0, application is 1
                                pcb->priority = priority;
                                pcb->pcb_state = 1;
                                pcb->isSuspended = 1;
                                pcb->memorySize = prog_len_p;
                                pcb->load_address = (unsigned char*)sys_alloc_mem(prog_len_p);
                                pcb->exec_address = pcb->load_address + start_offset_p;
                                //initialize context area of stack
                                pcbContext = (context *) pcb->stack_top; //link the context to the stack
                                pcbContext->IP = FP_OFF(pcb->exec_address); //set the offset for IP and FP based on the exec address computed above
                                pcbContext->CS = FP_SEG(pcb->exec_address); 
                                pcbContext->FLAGS = 0x200; 
                                pcbContext->DS = _DS; 
                                pcbContext->ES = _ES; 
                                LProg = sys_load_program(pcb->load_address, pcb->memorySize, dirName, programName);
                                if(LProg == 0){
                                        printf("Program Loaded\n");
                                        printf("Inserting into ready\n");
                                        insert_ready(pcb);
                                } else {
                                        printf("Program did NOT load. Error %d\n", LProg);
                                }
                        } else if(SCP == ERR_SUP_NAMLNG){
                                printf("Could not load program: name was too long!\n");//print error
                        } else if(SCP == ERR_SUP_FILNFD){
                                printf("Could not load program: File specified was not found.\n");//print error
                        } else if(SCP == ERR_SUP_FILINV){ 
                                printf("Could not load program: File contents not a valid program.\n");//print error
                        }
                } else {
                        printf("Process already exists\n");
                }
        } else {
                printf("Priority is invalid\n");
        }
}

void terminate_process(char processName[9]){
        MPX_PCB* newpcb;
        //MPX_PCB* find_ready(char processName[9]);
        //MPX_PCB* find_blocked(char processName[9]);
        newpcb = find_ready(processName);
        if(newpcb != NULL){
                if(newpcb->processClass == 0){
                        printf("PCB '%s' is a system function and cannot be deleted.\n", processName);
                }else{
                        removePCB(newpcb, 1);
                        sys_free_mem(newpcb->load_address);
                        sys_free_mem(newpcb->stack_base);
                        freePCB(newpcb);
                        printf("PCB '%s' deletion successful.\n",processName);
                }
        } else{
                newpcb = find_blocked(processName);
                if(newpcb != NULL){
                        if(newpcb->processClass == 0){
                                printf("PCB '%s' is a system function and cannot be deleted.\n", processName);
                        }else{
                                removePCB(newpcb, 0);
                                sys_free_mem(newpcb->load_address);
                                sys_free_mem(newpcb->stack_base);
                                freePCB(newpcb);                                
                                printf("PCB '%s' deletion successful.\n",processName);
                        }
                } else printf("PCB not found.\n");
        }
}

void new_dispatch(){

}

// some dashes/r4 commands a few more dashes //
